#include <stdio.h>
#include <pthread.h>
#include <modbus.h>
#include "shmem.h"
#include "cJSON.h"
#include "list.h"
#include "msg_queue_peer.h"

// 共享内存结构体
union val_t
{
    int b_val;   // bool类型存储空间
    int i_val;   // 整形值存储空间
    float f_val; // 浮点值存储空间
};

struct device
{
    int key;             // 唯一键值
    int type;            // 数据点类型
    int dev_type;        // 数据点属于哪个设备，根据网关支持的设备自行定义
    union val_t old_val; // 变化上报后需要更新旧值
    union val_t new_val; // 从共享内存取出最新数据，放到new_val中
    int ret;             // 默认为-1，采集成功后设置为0，采集失败再置-1
};

static int *total;              // 指向共享内存中数据节点总个数
static struct device *node_arr; // 指向共享内存中节点缓存数组头
static struct shm_param para;

#define MAX_NODE 128                            // 最大支持设备数目，实际可用是127
#define STD_NODE_LEN sizeof(struct device)      // 单个设备的结构体大小
#define MAX_NODE_SIZE (MAX_NODE * STD_NODE_LEN) // 共享内存总大小

// 消息队列结构体
struct msgbuf
{
    long mtype;
    char mdata[256];
};

// 链表节点数据结构定义
struct mb_node
{
    int key;        // 唯一键值
    char name[128]; // 数据点名称
    int type;       // 数据点类型
    int addr;       // 数据包头（地址）
};

struct mb_node_list
{
    struct mb_node node;
    struct list_head list;
};

struct list_head head;    // 链表头
struct mb_node_list *tmp; // 临时节点指针
struct list_head *pos;    // 遍历位置指针

// 读取线程(共享内存)
void *output_thread(void *arg)
{
    modbus_t *modbus = (modbus_t *)arg;
    int ret = -1;

    ret = shm_init(&para, "shm_test", MAX_NODE_SIZE);
    if (ret < 0)
    {
        return NULL;
    }
    void *node_p = shm_getaddr(&para);
    if (node_p == NULL)
    {
        return NULL;
    }
    // 前4个字节存储实际的设备数目
    total = (int *)node_p;
    int n = *total;
    // 后面空间存储数据点
    node_arr = (struct device *)(node_p + sizeof(int));

    uint8_t coil_values[5] = {0};        // 线圈寄存器值（0-4）
    uint16_t holding_register_value[5] = {0}; // 保持寄存器值（地址5）

    while (1)
    {
        // memset(node_p, 0, MAX_NODE_SIZE);
        int read1 = modbus_read_bits(modbus, 0, 5, coil_values);
        if (read1 == -1)
        {
            perror("bit read err\n"); // 读取失败
            return NULL;
        }
        int read2 = modbus_read_registers(modbus, 0, 1, holding_register_value);
        if (read2 == -1)
        {
            perror("bit read err\n"); // 读取失败
            return NULL;
        }

        for (int i = 0; i < n; i++)
        {
            node_arr[i].old_val.i_val = node_arr[i].new_val.i_val;
            if (node_arr[i].key == 101) // 空调开关
            {
                node_arr[i].new_val.i_val = coil_values[0];
            }
            else if (node_arr[i].key == 102) // 空调温度
            {
                node_arr[i].new_val.i_val = holding_register_value[0];
            }
            else if (node_arr[i].key == 103) // 加湿器
            {
                node_arr[i].new_val.i_val = coil_values[1];
            }
            else if (node_arr[i].key == 104) // 窗帘
            {
                node_arr[i].new_val.i_val = coil_values[2];
            }
            else if (node_arr[i].key == 105) // 扫地机器人
            {
                node_arr[i].new_val.i_val = coil_values[3];
            }
            else if (node_arr[i].key == 106) // 洗衣机
            {
                node_arr[i].new_val.i_val = coil_values[4];
            }
            //printf("node_arr[%d].new_val.i_val = %d\n", i, node_arr[i].new_val.i_val);
        }
        sleep(1);
    }
    return NULL;
}

// 控制线程(消息队列)
void *control_thread(void *arg)
{

    modbus_t *modbus = (modbus_t *)arg;
    struct msgbuf recv_buf;

    while (1)
    {
        if (msg_queue_recv("topic", &recv_buf, sizeof(recv_buf), 2, 0) > 0)
        {
            printf("recv from msga type = %ld\n", recv_buf.mtype);
            printf("recv from msga data = %s\n", recv_buf.mdata);

            int number, val;
            sscanf(recv_buf.mdata, "%d+%d", &number, &val); // 假设发来的是"101+1"
            printf("number = %d, value = %d\n", number, val);

            uint16_t value = (uint16_t)val;

            // cJSON *root = cJSON_Parse(recv_buf.mdata);
            // if (!root)
            // {
            //     printf("JSON parse failed\n");
            //     continue;
            // }

            // cJSON *key = cJSON_GetObjectItem(root, "key");
            // cJSON *val = cJSON_GetObjectItem(root, "val");
            // if (!cJSON_IsNumber(key) || !cJSON_IsNumber(val))
            // {
            //     printf("Invalid JSON format\n");
            //     cJSON_Delete(root);
            //     continue;
            // }

            // int number = key->valueint;
            // uint16_t value = atoi(val->valuestring);

            list_for_each(pos, &head)
            {

                tmp = list_entry(pos, struct mb_node_list, list);
                if (tmp->node.key == number)
                {
                    if (number == 101)
                    {
                        modbus_write_bit(modbus, tmp->node.addr - 1, value);
                    }
                    else if (number == 102)
                    {
                        modbus_write_register(modbus, tmp->node.addr - 40001, value);
                    }
                    else if (number == 103)
                    {
                        modbus_write_bit(modbus, tmp->node.addr - 1, value);
                    }
                    else if (number == 104)
                    {
                        modbus_write_bit(modbus, tmp->node.addr - 1, value);
                    }
                    else if (number == 105)
                    {
                        modbus_write_bit(modbus, tmp->node.addr - 1, value);
                    }
                    else if (number == 106)
                    {
                        modbus_write_bit(modbus, tmp->node.addr - 1, value);
                    }
                }
            }
            // cJSON_Delete(root); // 释放JSON对象
        }
        else
        {
            perror("msg_queue_recv error");
            usleep(100000); // 100ms延时
        }
    }
    return NULL;
}

int main(int argc, char *argv[])
{
    INIT_LIST_HEAD(&head);
    FILE *fp = fopen("data.json", "r+");
    if (fp == NULL)
    {
        perror("fopen err\n");
        return -1;
    }

    fseek(fp, 0, SEEK_END);
    long len = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    char *p = (char *)malloc(len + 1);
    fread(p, 1, len, fp);
    cJSON *root = NULL;
    root = cJSON_Parse(p);
    if (!root)
    {
        printf("JSON parse failed\n");
        return -1;
    }

    char *ver = cJSON_GetObjectItem(root, "version")->valuestring;
    printf("version=%s\n", ver);

    cJSON *DEV = cJSON_GetObjectItem(root, "mb_dev");
    char *ADDR = cJSON_GetObjectItem(DEV, "addr")->valuestring;
    printf("addr=%s\n", ADDR);
    int port = cJSON_GetObjectItem(DEV, "port")->valueint;
    printf("port=%d\n", port);

    // 解析modbus并插入链表
    cJSON *MOD = cJSON_GetObjectItem(root, "modbus");
    cJSON *DATA = cJSON_GetObjectItem(MOD, "data");
    int DA_size = cJSON_GetArraySize(DATA);
    cJSON *DA_item = DATA->child;

    for (int i = 0; i < DA_size; i++)
    {
        struct mb_node_list *arr = (struct mb_node_list *)malloc(sizeof(struct mb_node_list));
        printf("key:%d\n", cJSON_GetObjectItem(DA_item, "key")->valueint);
        printf("name:%s\n", cJSON_GetObjectItem(DA_item, "name")->valuestring);
        printf("type:%d\n", cJSON_GetObjectItem(DA_item, "type")->valueint);
        printf("addr:%d\n", cJSON_GetObjectItem(DA_item, "addr")->valueint);

        arr->node.key = cJSON_GetObjectItem(DA_item, "key")->valueint;
        arr->node.addr = cJSON_GetObjectItem(DA_item, "addr")->valueint;
        list_add(&arr->list, &head);
        DA_item = DA_item->next;
    }

    int slave = 1;           // 从站设备ID
    uint16_t dest[12] = {0}; // 存储读取结果的缓冲区
    // 创建Modbus
    modbus_t *modbus = modbus_new_tcp(ADDR, port);

    free(p);
    p = NULL;
    cJSON_Delete(root);

    if (modbus == NULL)
    {
        perror("modbus err\n"); // 创建上下文失败
        return -1;
    }

    // 设置从站ID
    if (modbus_set_slave(modbus, slave) < 0)
    {
        perror("modbus_set_slave err\n");
        return -1;
    }

    // 连接到Modbus服务器
    int connect = modbus_connect(modbus);
    if (connect == -1)
    {
        perror("conncet err\n"); // 连接失败
        return -1;
    }
    pthread_t tid_ctrl, tid_output;

    // 创建控制线程(消息队列)
    pthread_create(&tid_ctrl, NULL, control_thread, modbus);
    pthread_detach(tid_ctrl);

    // 创建读取线程(共享内存)
    pthread_create(&tid_output, NULL, output_thread, modbus);
    pthread_join(tid_output, NULL);

    //  关闭连接并释放资源
    modbus_close(modbus);
    modbus_free(modbus);

    return 0;
}
